from bcat.gtp.serde.error import ExpectTypeError
from bcat.gtp.serde.writer import Writer

class BytesWriter(Writer):
    @staticmethod
    def default():
        return BytesWriter(bytearray()) 

    def __init__(self, byte_buffer):
        super().__init__(byte_buffer)

    def _write_bytes(self, bs):
        len_bytes = len(bs)
        if len_bytes > 0:
            l = len(self.target())
            self.target()[l:l+len_bytes] = bs
        return len_bytes

    def clear(self):
        del self.target()[0:]

    def len(self):
        return len(self.target())

    def discard_back(self, n):
        del self.target()[self.len() - n:]
        return n

    def __str__(self):
        return "BytesWriter--target:{}".format(self.target())

import unittest
class TestWriter(unittest.TestCase):
    def test_write_str(self):
        expect = b'abcdedfffff'
        s = expect.decode()

        writer = BytesWriter.default()
        self.assertEqual(len(expect), writer.write_str(s))

        self.assertEqual(expect, writer.target())

    def test_uint_length(self):
        writer = BytesWriter.default()
        self.assertEqual(1, writer.write_uint8(0xF3))
        print(writer.target())

        writer.clear()
        self.assertEqual(2, writer.write_uint16(0xF203))
        print(writer.target())

        writer.clear()
        self.assertEqual(4, writer.write_uint32(0xF3031203))
        print(writer.target())

        writer.clear()
        self.assertEqual(8, writer.write_uint64(0xF4038532F3031203))
        print(writer.target())


    def test_int_length(self):
        writer = BytesWriter.default()
        self.assertEqual(1, writer.write_int8(0x73))
        print(writer.target())

        writer.clear()
        self.assertEqual(2, writer.write_int16(0x7203))
        print(writer.target())

        writer.clear()
        self.assertEqual(4, writer.write_int32(0x73031203))
        print(writer.target())

        writer.clear()
        self.assertEqual(8, writer.write_int64(0x74038532F3031203))
        print(writer.target())

    def test_bool(self):
        writer = BytesWriter.default()
        self.assertEqual(1, writer.write_bool(True))
        self.assertEqual(writer.target()[0], 1)
    
        writer.clear();
        self.assertEqual(1, writer.write_bool(False))
        self.assertEqual(writer.target()[0], 0)

    def test_float(self):
        writer = BytesWriter.default()
        self.assertEqual(0, writer.write_float(0.1))
        #TODO: self.assertEqual(writer.target(), 1)
        

    def test_uint_length_error(self):
        #TODO:
        pass
    def test_int_length_error(self):
        #TODO:
        pass

    def test_write_str_type_error(self):
        with self.assertRaises(ExpectTypeError):
            writer = BytesWriter.default()
            writer.write_str(None)
    

class TestBytesWriter_1(unittest.TestCase):

    def test_init(self):
        # Test initialization with a byte buffer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        self.assertEqual(writer.target(), byte_buffer)

    def test_discard_back(self):
        # Test the discard_back method
        byte_buffer = bytearray([1, 2, 3, 4, 5])
        writer = BytesWriter(byte_buffer)
        writer.discard_back(2)
        self.assertEqual(writer.target(), bytearray([1, 2, 3]))

    def test_clear(self):
        # Test the clear method
        byte_buffer = bytearray([1, 2, 3, 4, 5])
        writer = BytesWriter(byte_buffer)
        writer.clear()
        self.assertEqual(writer.target(), bytearray())

    def test_write_bytes(self):
        # Test writing bytes
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_bytes(b'hello')
        self.assertEqual(writer.target(), b'hello')

    def test_write_str(self):
        # Test writing a string
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_str('world', encoding='utf-8')
        self.assertEqual(writer.target(), b'world')

    def test_write_uint8(self):
        # Test writing an unsigned 8-bit integer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_uint8(10)
        self.assertEqual(writer.target(), b'\x0a')

    def test_write_uint16(self):
        # Test writing an unsigned 16-bit integer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_uint16(256)
        self.assertEqual(writer.target(), b'\x00\x01')

    def test_write_uint32(self):
        # Test writing an unsigned 32-bit integer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_uint32(1000000)
        self.assertEqual(writer.target(), b'\x00\x0f\x42\x40')

    def test_write_uint64(self):
        # Test writing an unsigned 64-bit integer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_uint64(10000000000000000000)
        self.assertEqual(writer.target(), b'\x00\x00\x00\x00\x00\x00\xf4\x24\x00\x00\x00\x00\x00\x00\x00\x00')

    def test_write_int8(self):
        # Test writing a signed 8-bit integer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_int8(-10)
        self.assertEqual(writer.target(), b'\xf6')

    def test_write_int16(self):
        # Test writing a signed 16-bit integer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_int16(-256)
        self.assertEqual(writer.target(), b'\xff\x00')

    def test_write_int32(self):
        # Test writing a signed 32-bit integer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_int32(-1000000)
        self.assertEqual(writer.target(), b'\xff\xf0\xbd\xc0')

    def test_write_int64(self):
        # Test writing a signed 64-bit integer
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_int64(-10000000000000000000)
        self.assertEqual(writer.target(), b'\xff\xff\xff\xff\xff\xff\xf4\x24\x00\x00\x00\x00\x00\x00\x00')

    def test_write_float(self):
        # Test writing a float (TODO: implement actual test)
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_float(3.14)
        # self.assertEqual(writer.target(), b'...')  # Replace with expected result

    def test_write_bool(self):
        # Test writing a boolean
        byte_buffer = bytearray()
        writer = BytesWriter(byte_buffer)
        writer.write_bool(True)
        self.assertEqual(writer.target(), b'\x01')
        writer.write_bool(False)
        self.assertEqual(writer.target(), b'\x00')

if __name__ == '__main__':
    unittest.main()
